package com.xtpt.disaster.common.File;

import com.xtpt.disaster.bean.DbnodeInfo;
import com.xtpt.disaster.bean.JobDetail;
import com.xtpt.disaster.bean.NodeInfo;
import com.xtpt.disaster.bean.TaskInfo;
import com.xtpt.disaster.common.ClientCmdBuilder;
import com.xtpt.disaster.common.PropertyConfig;
import com.xtpt.disaster.common.consts.BackupTypeEnum;
import com.xtpt.disaster.common.consts.DataTypeEnum;
import com.xtpt.disaster.common.consts.OSTypeEenum;
import com.xtpt.disaster.utils.LogUtil;
import com.xtpt.disaster.utils.ServerPathUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.util.HashMap;
import java.util.List;
import java.util.Map;

import static com.xtpt.disaster.utils.ServerPathUtil.IsFolderAndGetLastPart;
import static com.xtpt.disaster.utils.ServerPathUtil.TrimPathEndSeparator;

/**
 * @author jack_xin
 * @ClassName FileCmdBuild
 * @Desc TODO
 * @date 2021年12月23日 18:01
 * @Version TODO
 */
@Component
public class FileCmdBuilder extends ClientCmdBuilder {
    @Autowired
    PropertyConfig config;

    @Autowired
    ServerPathUtil pathUtil;

    /**
     * 客户端操作系统类型
     */
    private OSTypeEenum osType;

    /**
     * 客户端节点信息
     */
    private NodeInfo clientInfo;
    /**
     * 构造函数
     * @throws Exception 异常
     */
    public FileCmdBuilder(){
        super();
    }

    public FileCmdBuilder setOSType(OSTypeEenum osType) throws Exception
    {
        this.osType = osType;
        super.setOSType(this.osType);
        return this;
    }
    /**
     * @Description: 生成列出文件目录的命令
     * @Author: hpc
     * @Date: 2022/1/9 下午 12:54
     * @param folderAbsolutePath:
     * @return: com.xtpt.disaster.common.File.FileCmdBuilder
     **/
    public FileCmdBuilder listFilesInPath(String folderAbsolutePath) throws Exception {
        String cmd;
        if(OSTypeEenum.LINUX == this.osType)
        {
            cmd = "find /opt -type f  | tr '\\n' '\\0' | xargs -0 ls -la --time-style '+|%Y/%m/%d  %H:%M:%S|'";
        }
        else if(OSTypeEenum.WINDOWS == this.osType)
        {
            cmd = "cmd.exe /c dir %s /s/a-d/-c";
        }
        else
        {
            throw new Exception("系统类型不支持！");
        }
        AddCmdWithNewGroup(String.format(cmd, folderAbsolutePath));
        return this;
    }

    /**
     * 设置客户端节点信息
     * @param nodeInfo 客户端节点
     * @return this
     * @throws Exception
     */
    public FileCmdBuilder initializeWithClientNode(NodeInfo nodeInfo) throws Exception {
        //设置客户端则初始化父类
        super.init();
        this.clientInfo=nodeInfo;
        this.setOSType(OSTypeEenum.getObject(nodeInfo.getOsType()));
        return this;
    }

    /*
     * @Author jack xin
     * @Method Name dbSQLServerBackUp
     * @Desc 执行生成的备份命令，放入一个命令组中执行，返回Map<备份文件所在的本地路径, 服务器存储的路径>
     * @Param [taskId, backFileName, FullOrIncrement, disc, backFlag]
     * @return java.util.Map<java.lang.String,java.lang.String>
     * @Date 11:20 2021/12/8
     **/
    public Map<String,String> fileBackUp(TaskInfo taskInfo, Integer dataType, String backupFileName) {
        Map<String,String> pathMap = new HashMap<>();
        String taskId = taskInfo.getTaskId().toString();
        //生成本地备份文件的全文件名
//        String fullFileName = backupFileName;
        String createdFolder = IsFolderAndGetLastPart(taskInfo.getTaskClientPath());
        //生成服务器路径，fileServerRootPath不是最终路径，还需要拼接"_" + fullFileName
        DataTypeEnum backupDataType = DataTypeEnum.getObject(dataType);
        String fileServerRootPath = pathUtil.getServerFileBackupPath(taskId, backupDataType, createdFolder);
        if(createdFolder!=null)
        {
            // 此时备份为文件夹备份
            backupFileName=null;
        }
        //获取客户端需要备份的文件的绝对路径
        String clientFilePath = ServerPathUtil.TrimPathEndSeparator(taskInfo.getTaskClientPath());
        //生成最终的文件在备份存储服务器上的绝对路径
        String serverFilePath = combinePath(fileServerRootPath,backupFileName);
        // 实际数据库备份流程，通过conn语句在客户端上连接数据库，然后执行备份指令sql，备份完成后退出，最后使用scp或者pscp命令传输备份文件到服务器上。
        TransactionFilesToServer(clientFilePath,serverFilePath);
        // 位置不能放到 TransactionFilesToServer() 前
        if(createdFolder!=null)
        {
            // 表明是文件夹备份 改变数据库中存储的内容
            serverFilePath=combinePath(serverFilePath,createdFolder);
        }
        pathMap.put(serverFilePath, clientFilePath);
        return pathMap;
    }

    /**
     * 仅用于文件夹的增量备份
     * @param inputClientPath 前端输入的要备份的文件夹路径
     * @param serverPath 查询数据库获取的最近一次成功的文件夹全量备份服务端路径
     * @param clientFilePath 查询数据库获取的最近一次成功的文件夹全量备份客户端路径
     * @return
     */
    public Map<String,String> fileIncrementBackUp(String inputClientPath, String serverPath, String clientFilePath) {
        Map<String,String> pathMap = new HashMap<>();
        //生成本地备份文件的全文件名
//        String fullFileName = backupFileName;
        String createdFolder = IsFolderAndGetLastPart(inputClientPath);
        if(createdFolder==null)
        {
            LogUtil.logger.error("不是文件夹不能进行增量备份！");
            createdFolder = "";
        }
        //生成最终的文件在备份存储服务器上的绝对路径
        String serverFilePath = serverPath.substring(0,serverPath.length()-createdFolder.length());
        // 实际数据库备份流程，通过conn语句在客户端上连接数据库，然后执行备份指令sql，备份完成后退出，最后使用scp或者pscp命令传输备份文件到服务器上。
        TransactionFilesToServer(clientFilePath,serverFilePath, BackupTypeEnum.INCREMENT);
        pathMap.put(serverPath, clientFilePath);
        return pathMap;
    }

    /*
     * @Author jack xin
     * @Method Name dbSQLServerRecover
     * @Desc 执行生成的备份命令，放入一个命令组中执行，返回Map<备份文件所在的本地路径, 服务器存储的路径>
     * @Param [taskId, backFileName, FullOrIncrement, disc, backFlag]
     * @return java.util.Map<java.lang.String,java.lang.String>
     * @Date 11:20 2021/12/8
     **/
    public Map<String, String> fileRecover(JobDetail jobDetail) {
        Map<String,String> pathMap = new HashMap<>();
        String clientFilePath = jobDetail.getClientPath();
        String serverPath = jobDetail.getServerPath();
        //去除末尾的路径分隔符
        clientFilePath = TrimPathEndSeparator(clientFilePath);
        //取出恢复目标的上层绝对路径
        int end = clientFilePath.length();
        if(clientFilePath.indexOf(":\\")>0)
        {
            if(clientFilePath.indexOf(":\\")+2<clientFilePath.lastIndexOf("\\"))
            {
                end = clientFilePath.lastIndexOf("\\");
            }
        }
        else if(clientFilePath.startsWith("/"))
        {
            if(clientFilePath.lastIndexOf("/")>0)
            {
                end = clientFilePath.lastIndexOf("/");
            }
        }
        clientFilePath=clientFilePath.substring(0,end);
        TransactionFileToClient(serverPath, clientFilePath);
        pathMap.put(clientFilePath, serverPath);
        return pathMap;
    }

    @Override
    public Map<String, String> dbBackUp(String taskId, String backFileName, String FullOrIncrement, String disc, String backFlag) throws Exception {
        return null;
    }

    @Override
    public ClientCmdBuilder dbRestore(String mainRestoreFilePathOnClient, List<String> allBackupFiles) {
        return null;
    }

    //////////////////////////////////////////////////// 如下重写父类方法
    /**
     * 新添加命令组并将命令加入到新组（自动加回车符）
     * @param cmd 命令字符串
     * @return this
     */
    public FileCmdBuilder AddCmdLn(String cmd)
    {
        super.AddCmdLn(cmd);
        return this;
    }

    /**
     * 新添加命令组并将命令加入到新组（自动加回车符）
     * @param cmd 命令字符串
     * @return this
     */
    public FileCmdBuilder AddCmd(String cmd)
    {
        super.AddCmd(cmd);
        return this;
    }
    /**
     * 新添加命令组并将命令加入到新组（自动加回车符）
     * @param cmd 命令字符串
     * @return this
     */
    public FileCmdBuilder AddCmdWithNewGroupLn(String cmd)
    {
        super.AddCmdWithNewGroupLn(cmd);
        return this;
    }

    @Override
    public ClientCmdBuilder initializeWithClientNode(DbnodeInfo nodeInfo) throws Exception {
        return null;
    }

    /**
     * 新添加命令组并将命令加入到新组（自动加回车符）
     * @param cmd 命令字符串
     * @return this
     */
    public FileCmdBuilder AddCmdWithNewGroup(String cmd)
    {
        super.AddCmdWithNewGroup(cmd);
        return this;
    }


}
